package com.ghy.ic.mo;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.ghy.ic.mo.controller.ManageController;
import com.ghy.ic.mo.controller.QyOauthController;
import com.ghy.ic.mo.controller.UserController;
import com.ghy.ic.mo.dao._MappingKit;
import com.ghy.ic.mo.task.ShuttleBusAddTask;
import com.ghy.ic.mo.task.WatchDogTask;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.jfinal.config.*;
import com.jfinal.core.JFinal;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.cron4j.Cron4jPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.qyweixin.sdk.api.ApiConfig;
import com.jfinal.qyweixin.sdk.api.ApiConfigKit;
import com.jfinal.render.ViewType;
import com.jfinal.template.Engine;

import java.io.File;
import java.util.concurrent.*;

import static java.util.concurrent.Executors.newSingleThreadExecutor;

/**
 * 用于全局的配置和启动
 * @author Y-Tree
 * @date 18-11-28 下午2:48
 */
public class BookCarServiceApplication extends JFinalConfig {

    /**
     * 如果要支持多公众账号，只需要在此返回各个公众号对应的 ApiConfig 对象即可 可以通过在请求 url 中挂参数来动态从数据库中获取
     * ApiConfig 属性值
     */
    public ApiConfig getApiConfig() {
        ApiConfig ac = new ApiConfig();

        // 配置微信 API 相关常量
        ac.setToken(PropKit.get("token"));
        ac.setCorpId(PropKit.get("corpId"));
        ac.setCorpSecret(PropKit.get("secret"));
        ac.setAgentId(PropKit.get("agentId"));

        /**
         * 是否对消息进行加密，对应于微信平台的消息加解密方式： 1：true进行加密且必须配置 encodingAesKey
         * 2：false采用明文模式，同时也支持混合模式
         */
        ac.setEncryptMessage(PropKit.getBoolean("encryptMessage", true));
        ac.setEncodingAesKey(PropKit.get("encodingAesKey", "setting it in config file"));
        return ac;
    }

    /**
     * 如果生产环境配置文件存在，则优先加载该配置，否则加载开发环境配置文件
     *
     * @param pro
     *            生产环境配置文件
     * @param dev
     *            开发环境配置文件
     */
    private void loadProp(String pro, String dev) {
        try {
            PropKit.use(pro);
        } catch (Exception e) {
            PropKit.use(dev);
        }
    }

    /**
     * 配置常量
     * 加载少量必要配置，随后可用PropKit.get(...)获取值
     */
    @Override
    public void configConstant(Constants constants) {

        loadProp("pro_coffee_config.txt", "dev_coffee_config.txt");
        constants.setDevMode(PropKit.getBoolean("devMode", false));
        constants.setEncoding("utf-8");
        constants.setViewType(ViewType.JSP);

        // 设置上传文件保存的路径
        constants.setBaseUploadPath(PathKit.getWebRootPath() + File.separator + "upload");
        // 文件下载路径
        constants.setBaseDownloadPath(PathKit.getWebRootPath() + "download");
        // ApiConfigKit 设为开发模式可以在开发阶段输出请求交互的 xml 与 json 数据
        ApiConfigKit.setDevMode(constants.getDevMode());
    }

    /**
     * 路由配置
     */
    @Override
    public void configRoute(Routes routes) {

        // 管理员相关操作
        routes.add("/manage", ManageController.class);
        // 用户相关操作
        routes.add("/user", UserController.class);
        // 获取用户信息
        routes.add("/oauth", QyOauthController.class);
    }


    @Override
    public void configEngine(Engine engine) {
        // nothing
    }

    /**
     * 配置创建druidPlugin插件
     */
    public static DruidPlugin createDruidPlugin(){
        String jdbcUrl = PropKit.get("jdbcUrl");
        String user = PropKit.get("user");
        String password = PropKit.get("password");

        // 配置druid数据连接池插件
        DruidPlugin dp = new DruidPlugin(jdbcUrl, user, password);
        // 配置druid监控
        dp.addFilter(new StatFilter());
        WallFilter wall = new WallFilter();
        wall.setDbType("mysql");
        dp.addFilter(wall);
        return dp;
    }

    /**
     * 配置数据库
     */
    @Override
    public void configPlugin(Plugins plugins) {

        // 配置DruidPlugin
        DruidPlugin druidPlugin = createDruidPlugin();
        plugins.add(druidPlugin);
        ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
        _MappingKit.mapping(arp);
        plugins.add(arp);

        // 配置定时任务
        Cron4jPlugin cp = new Cron4jPlugin();
        cp.addTask("30 17 * * *", new ShuttleBusAddTask());
        plugins.add(cp);

    }

    @Override
    public void configInterceptor(Interceptors interceptors) {
        // nothing
    }

    @Override
    public void configHandler(Handlers handlers) {
        // nothing
    }

    /**
     * 启动之后就执行下面代码
     */
    @Override
    public void afterJFinalStart() {
        ApiConfigKit.putApiConfig(getApiConfig());

        // 自动为数据库添加记录15天记录
        WatchDogTask task = new WatchDogTask();
        // 创建一个单线程的线程池 类似于Executor.newSingleThreadExecutor
        ThreadFactory build = new ThreadFactoryBuilder().setNameFormat("WatchDog-pool-%d").build();
        ThreadPoolExecutor singleThreadPool = new ThreadPoolExecutor(1, 1,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(), build, new ThreadPoolExecutor.AbortPolicy());
        // 将任务放入线程池中
        singleThreadPool.submit(task);
    }

    /**
     * 建议使用 JFinal 手册推荐的方式启动项目 运行此 main
     * 方法可以启动项目，此main方法可以放置在任意的Class类定义中，不一定要放于此
     * 启动配置项
     */
    public static void main(String[] args) {
        JFinal.start("src/main/webapp", 8080, "/", 5);
    }
}
